Repository navigation
feat(mcp): improve retrieval quality with phrase bonus, community coherence, and evidence-first truncation (#3810) - #3866
Conversation
|
Thanks for the pull request, @nikhilsaxena04. A maintainer will review it soon. Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions. A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic. |
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.
Graphify review — findings
Adds a sub-phrase scoring tier to _score_query that, for queries of 3+ terms, awards a single best (longest-wins) bonus when the label contains a contiguous 2- or 3-gram of the query, weighted by the phrase's max IDF — so Incidence Algebra outranks a bare Incidence match. Reorders _pick_seeds when seed count exceeds max_k and a graph is present, stable-sorting the majority-community seeds first before truncating. Prioritizes nodes lying on inter-seed shortest paths in _subgraph_to_text (capped at ~2 pairs per seed to bound cost) so those evidence nodes survive token-budget truncation ahead of high-degree neighbors.
Worth a look
- _pick_seeds community reorder can drop a per-term guaranteed seed —
graphify/serve.py:871· Escalate · high · 2 independent checks- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Phrase bonus matches across word boundaries —
graphify/serve.py:674· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 621 functions depend on the 360 functions this change touches.
Health — this change adds coupling hotspots:
- new:
main()— 98 callers, 3 callees - new:
_query_graph_text()— 28 callers, 10 callees - new:
dispatch_command()— 2 callers, 125 callees - new:
_score_query()— 17 callers, 7 callees - new:
_query_terms()— 20 callers, 3 callees - new:
run_benchmark()— 16 callers, 3 callees - new:
_load_graph()— 16 callers, 3 callees - new:
_build_server()— 2 callers, 16 callees - …and 11 more — each is listed as a finding
Verification — 621 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 436 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
9 of 302 test file(s) selected (3%) via static blast radius.
tests/test_benchmark.py— impacttests/test_benchmark_raw_graph.py— impacttests/test_file_label_disambiguation.py— impacttests/test_query_induced_edges.py— impacttests/test_query_mcp_direction.py— impacttests/test_query_names_its_graph.py— impacttests/test_serve.py— impact, changed-testtests/test_serve_http.py— impacttests/test_terraform.py— impact
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
· 19 more finding(s) on lines outside this diff (see the check run).
1442261 to
27c42b2
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Graphify review — findings
Adds a sub-phrase scoring tier in _score_query so that for queries of 3+ terms, contiguous 2- and 3-gram matches against a node's label (word-boundary checked) earn a bonus scaled by the longest matching phrase's IDF, letting "Incidence Algebra" outrank a bare "Incidence" hit; only the longest phrase per node scores. Reworks _pick_seeds to collect all gap-passing candidates first and, when they exceed max_k, prefer seeds from the dominant community before truncating, so a lone high-scoring outlier community doesn't crowd out a coherent cluster. Reorders _subgraph_to_text output to place nodes lying on inter-seed shortest paths (evidence nodes, capped at a few pairs per seed) ahead of other nodes, so connecting-path nodes survive token-budget truncation.
Worth a look
- _pick_seeds no longer returns highest-scoring seeds when truncating —
graphify/serve.py:862· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 621 functions depend on the 360 functions this change touches.
Health — this change adds coupling hotspots:
- new:
main()— 98 callers, 3 callees - new:
_query_graph_text()— 28 callers, 10 callees - new:
dispatch_command()— 2 callers, 125 callees - new:
_score_query()— 17 callers, 7 callees - new:
_query_terms()— 20 callers, 3 callees - new:
run_benchmark()— 16 callers, 3 callees - new:
_load_graph()— 16 callers, 3 callees - new:
_build_server()— 2 callers, 16 callees - …and 11 more — each is listed as a finding
Verification — 621 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 436 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
9 of 302 test file(s) selected (3%) via static blast radius.
tests/test_benchmark.py— impacttests/test_benchmark_raw_graph.py— impacttests/test_file_label_disambiguation.py— impacttests/test_query_induced_edges.py— impacttests/test_query_mcp_direction.py— impacttests/test_query_names_its_graph.py— impacttests/test_serve.py— impact, changed-testtests/test_serve_http.py— impacttests/test_terraform.py— impact
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
· 19 more finding(s) on lines outside this diff (see the check run).
|
Hi @safishamsi! 👋 Just a quick note regarding the automated bot finding about The community filter only kicks in for nodes that have already passed the strict 20% score gap threshold. If we have multiple nodes clustered within 20% of the top score, we explicitly want to drop a slightly higher-scoring isolated outlier in favor of a cohesive cluster of slightly lower-scoring nodes that accurately represent the semantic domain. Truly dominant exact-matches are fully protected by the 20% gap and won't be truncated. Everything is fully regression tested. Let me know if you need any adjustments! |
|
Thanks @nikhilsaxena04 — the direction here is good and it's deterministic (no #1667 exposure); the sub-phrase bonus and evidence-first truncation are sound. Two blockers before it can land:
Non-blocking but worth doing given this targets large graphs: the evidence |
|
Thanks for this, @nikhilsaxena04 - the phrase-bonus and evidence-first truncation are both sound, deterministic, and address real gaps, so I'd like to land them. A few things to sort out first:
Happy to re-review once these are addressed. |
…erence, and evidence-first truncation (Graphify-Labs#3810) - Sub-phrase bonus in _score_query: Queries with 3+ terms now get a prefix match bonus for contiguous 2-gram or 3-gram subphrases found in the node label, allowing coherent multi-term matches to outrank incidental single-term matches. - Community coherence filter in _pick_seeds: When query terms yield more seeds than max_k, the set is truncated by favoring seeds belonging to the majority community among the seed set, preventing unrelated domains from hijacking the traversal. - Evidence-first truncation in _subgraph_to_text: Nodes along the shortest paths between seeds are now sorted ahead of arbitrary hop-distance neighbors, ensuring crucial structural evidence survives token-budget truncation. Co-Authored-By: Google Antigravity <noreply@google.com>
27c42b2 to
90d8ef5
Compare
|
Hi @safishamsi Thanks for the detailed review and catching those edge cases. I've addressed all the feedback in the latest push: 1. Reconciled community coherence with guaranteed seeds
2. Restored legacy parity test & added end-to-end regression tests
3. Shortest-path evidence on undirected induced subgraph
4. Retrieval benchmark numbersRan
5. Rebase & hygiene
All 221 tests in the serve and query suites are passing. Ready for re-review! |
What does this PR do?
Resolves #3810 (MCP Retrieval Quality)
This PR addresses the retrieval precision issues in the MCP agent context when dealing with large graphs. It implements three targeted improvements to the retrieval and rendering pipeline to surface the most relevant structural evidence:
_score_query): For queries with 3+ terms, it now applies a prefix match bonus for contiguous 2-gram or 3-gram subphrases found in the node label. This allows coherent multi-term identifier matches (e.g.,incidence algebra) to correctly outrank isolated, incidental single-term matches._pick_seeds): When query terms yield more seeds thanmax_k, the seed set is now truncated by prioritizing nodes that belong to the majority community among the seed pool. This prevents isolated nodes in completely unrelated semantic domains from stealing seed slots and hijacking the traversal._subgraph_to_text): Nodes lying on the inter-seed shortest path (the core structural evidence connecting queried symbols) are sorted first before other arbitrary neighbors. This guarantees they survive aggressive token-budget truncation cuts.Type of change
Verification & Invariants
Invariants Protected:
Legacy Exact Matching Parity: We ensure standard token queries keep their initial single-term matching fallback when sub-phrases aren't present.
Token Budgets:
_subgraph_to_textcontinues to strictly respect itschar_budgetthreshold; it just prioritizes critical structural path nodes first.Read the CONTRIBUTING.md guide.
Reproduced the issue and identified the invariant.
Made the smallest fix necessary.
Added a regression test (if bug fix) or isolated boundary test.
Kept the PR description synchronized with the final implementation.
Documented any limitations / unsupported cases explicitly.
How was this tested?
Ran the full serve test suite specifically targeting legacy parity, community isolation, and node truncation budgets. Tests executed on Python 3.10.